﻿namespace Zive.Color {

    /// <summary>CIE standard illuminants.</summary>
    public enum Illuminants {
        /// <summary>Incandescent/tungsten.</summary>
        A = 1,
        /// <summary>Direct sunlight at noon. (obsolete)</summary>
        B,
        /// <summary>Average/north sky daylight. (obsolete)</summary>
        C,
        /// <summary>Horizon light. White point for ICC profile PCS.</summary>
        D50,
        /// <summary>Mid-morning/mid-afternoon daylight.</summary>
        D55,
        /// <summary>Noon daylight. White point for television, sRGB.</summary>
        D65,
        /// <summary>North sky daylight.</summary>
        D75,
        /// <summary>Equal energy.</summary>
        E,
        /// <summary>Fluorescent: daylight.</summary>
        F1,
        /// <summary>Fluorescent: cool white.</summary>
        F2,
        /// <summary>Fluorescent: white.</summary>
        F3,
        /// <summary>Fluorescent: warm white.</summary>
        F4,
        /// <summary>Fluorescent: daylight.</summary>
        F5,
        /// <summary>Fluorescent: lite white.</summary>
        F6,
        /// <summary>Fluorescent: D65/daylight simulator.</summary>
        F7,
        /// <summary>Fluorescent: D50 simulator; Sylvania F40 Design 50.</summary>
        F8,
        /// <summary>Fluorescent: cool white deluxe.</summary>
        F9,
        /// <summary>Fluorescent: Philips TL85, Ultralume 50.</summary>
        F10,
        /// <summary>Fluorescent: Philips TL84, Ultralume 40.</summary>
        F11,
        /// <summary>Fluorescent: Philips TL83, Ultralume 30.</summary>
        F12
    };

    public static class IlluminantsExtensions {

        //
        // Data for illuminants A, B, C, D50, D55, D65, D75, E, F2, F7, F11 drawn from BruceLindbloom.com
        // Data for illuminants F1, F3, F4, F5, F6, F8, F9, F10, F12 drawn from Wikipedia
        //

        private static readonly double[ ][ , ] _referenceWhites = {
            null,
            /* A   */ new [ , ] { { 1.09850d }, { 1d }, { 0.35585d } },
            /* B   */ new [ , ] { { 0.99072d }, { 1d }, { 0.85223d } },
            /* C   */ new [ , ] { { 0.98074d }, { 1d }, { 1.18232d } },
            /* D50 */ new [ , ] { { 0.96422d }, { 1d }, { 0.82521d } },
            /* D55 */ new [ , ] { { 0.95682d }, { 1d }, { 0.92149d } },
            /* D65 */ new [ , ] { { 0.95047d }, { 1d }, { 1.08883d } },
            /* D75 */ new [ , ] { { 0.94972d }, { 1d }, { 1.22638d } },
            /* E   */ new [ , ] { { 1.00000d }, { 1d }, { 1.00000d } },
            /* F1  */ xy_to_XYZ( 0.31310d, 0.33727d ),
            /* F2  */ new [ , ] { { 0.99186d }, { 1d }, { 0.67393d } },
            /* F3  */ xy_to_XYZ( 0.40910d, 0.39430d ),
            /* F4  */ xy_to_XYZ( 0.44018d, 0.40329d ),
            /* F5  */ xy_to_XYZ( 0.31379d, 0.34531d ),
            /* F6  */ xy_to_XYZ( 0.37790d, 0.38835d ),
            /* F7  */ new [ , ] { { 0.95041d }, { 1d }, { 1.08747d } },
            /* F8  */ xy_to_XYZ( 0.34588d, 0.35875d ),
            /* F9  */ xy_to_XYZ( 0.37417d, 0.37281d ),
            /* F10 */ xy_to_XYZ( 0.34609d, 0.35986d ),
            /* F11 */ new [ , ] { { 1.00962d }, { 1d }, { 0.64350d } },
            /* F12 */ xy_to_XYZ( 0.43695d, 0.40441d ),
        };

        private static readonly string[ ] _descriptions = {
            null,
            /* A   */ "Incandescent/tungsten",
            /* B   */ "Direct sunlight at noon (obsolete)",
            /* C   */ "Average/north sky daylight (obsolete)",
            /* D50 */ "Horizon light; white point for ICC profile PCS",
            /* D55 */ "Mid-morning/mid-afternoon daylight",
            /* D65 */ "Noon daylight; white point for television, sRGB",
            /* D75 */ "North sky daylight",
            /* E   */ "Equal energy",
            /* F1  */ "Fluorescent: daylight",
            /* F2  */ "Fluorescent: cool white",
            /* F3  */ "Fluorescent: white",
            /* F4  */ "Fluorescent: warm white",
            /* F5  */ "Fluorescent: daylight",
            /* F6  */ "Fluorescent: lite white",
            /* F7  */ "Fluorescent: D65/daylight simulator",
            /* F8  */ "Fluorescent: D50 simulator; Sylvania F40 Design 50",
            /* F9  */ "Fluorescent: cool white deluxe",
            /* F10 */ "Fluorescent: Philips TL85, Ultralume 50",
            /* F11 */ "Fluorescent: Philips TL84, Ultralume 40",
            /* F12 */ "Fluorescent: Philips TL83, Ultralume 30",
        };

        private static double[ , ] xy_to_XYZ( double x, double y ) {
            return new[ , ] { { x / y }, { 1d }, { ( 1d - x - y ) / y } };
        }

        public static double[ , ] GetReferenceWhite( this Illuminants illuminant ) {
            return _referenceWhites[ (int) illuminant ];
        }

        public static string GetDescription( this Illuminants illuminant ) {
            return _descriptions[ (int) illuminant ];
        }

    }

}
